Repository navigation
feat!: wire the list_proposals and list_collections tasks - #1803
Conversation
Serve the experimental AdCP 3.3 reads from a DecisioningPlatform and close the gaps around them. - OpenOpportunitiesPlatform / CollectionCatalogPlatform hooks. PlatformHandler serves list_proposals when media_buy.lifecycle_tools lists it or open_opportunities.list_proposals is true, and list_collections when experimental_features lists media_buy.collection_catalog. Undeclared methods are not advertised; a declaration without a method fails validate_platform. list_collections resolves without an account. Both refuse a caller below 3.3 with UNSUPPORTED_FEATURE. - The dispatcher answers a task the caller's release does not define with UNSUPPORTED_FEATURE (details task, adcp_version) instead of VERSION_UNSUPPORTED, as the spec requires for list_collections. - The response-envelope helper treats both tasks like list_products: the 3.3 prereleases before beta.3 close their roots without status, so the bundled beta.1 / beta.2 list_collections examples now validate. - proposal.created: WebhookSender.prepare_proposal_created / send_proposal_created, schema-validated, notification_id bound to proposal_id. Agent-level notification configs classify the 3.3 account-anchored types, with a drift guard against the enum. - MCP tool stubs carry the 3.3 request fields; capability exports OpenOpportunities and LaterProposals; media-buy default trust scope covers both reads. BREAKING CHANGE: a server asked for a task its caller's release does not define now fails with UNSUPPORTED_FEATURE instead of VERSION_UNSUPPORTED. validate_platform fails when a platform declares list_proposals or media_buy.collection_catalog without the method. Agent-level notification registrations of proposal.created, proposal.offered, collection_card.*, collection_catalog.bulk_change or creative.staged_update_changed require all_authorized_accounts true. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…_collections Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Ladon verdict: Approve
Approve — clean review, no blocking or medium findings.
This PR serves the AdCP 3.3 experimental reads (list_proposals / list_collections) on PlatformHandler with declaration gating, boot validation, and UNSUPPORTED_FEATURE refusal of sub-3.3 callers, plus proposal.created webhook helpers.
Checked:
- The breaking error-code change (
VERSION_UNSUPPORTED→UNSUPPORTED_FEATUREfor a task the caller's release does not define) is correctly shipped asfeat!with migration notes (MIGRATION_v9_to_v10.md), satisfying the semver-signal gate. - No-double-missing reported guard (dispatch.py:971-978), task-not-defined narrowing (mcp_tools.py:3597-3615), optional-account handling (handler.py:1740), and notification_id==proposal_id ordering after schema validation (_notification_envelope.py:94-95).
- Comprehensive test coverage (new test_list_proposals_collections.py, 368 lines, including drift guard on account-anchored notification types).
High-risk flag is true only because the diff touches src/adcp/decisioning/** and src/adcp/server/** — all entries are (modified) or (added), none (deleted), and the reviewer surfaced no medium-or-higher concerns on the modified files. No escalation trigger. gated_paths is false; no author team gate. Falls through to row 9.
There was a problem hiding this comment.
Ladon verdict: Approve
Approve — subsequent pass, docstring-only delta since the prior approve.
The only change since the last approved run (b0ab5b1) is docstring edits in src/adcp/client.py for list_collections/list_proposals (single- and multi-agent): the feature id is renamed to media_buy.collection_catalog, the pre-send UNSUPPORTED_FEATURE refusal is documented, and list_proposals is reworded to "proposal snapshots and their dispositions." The reviewer confirms all text matches already-shipped behavior (experimental_reads.refuse_caller_below_release, the renamed capability) — no behavior change, no public surface touched, no over-threshold delta file.
Decision-table walk: no critical/high/medium findings (row 1 n/a). gated_paths is false and review_decision is APPROVED anyway (row 2 n/a). high_risk is true but all reasons are (modified)/(added) with zero findings — no (deleted), no medium on a modified sensitive file, so rows 3–5 do not fire. Prior decision was approve, not escalate (row 6 n/a). No no-auto-approve team match (row 7 n/a). Zero medium findings, so row 8 n/a. Falls through to row 9 → approve.
Nothing actionable surfaced.
Summary
Serves the experimental AdCP 3.3 reads
list_proposals(media_buy.open_opportunities) andlist_collections(media_buy.collection_catalog) end to end, against the pinned3.3.0-beta.3bundle. The client methods, multi-agent client,ADCPHandlerstubs, MCP/A2A adapters, CLI and MCP tool list were already registered onnext; this PR adds the seller framework side and the gaps around it.Decisioning hooks. New
OpenOpportunitiesPlatformandCollectionCatalogPlatformProtocols, exported fromadcp.decisioningand delegated byPlatformRouter.PlatformHandleradvertises and serves:list_proposalswhenmedia_buy.lifecycle_toolslists it ormedia_buy.open_opportunities.list_proposalsis true;list_collectionswhenexperimental_featureslistsmedia_buy.collection_catalog.A method with no declaration is not advertised. A declaration with no method fails
validate_platformat boot.list_collectionsresolves without an account. Both refuse a caller below 3.3 withUNSUPPORTED_FEATURE, including on a server whose handlers run on an older release.adcp.decisioning.capabilitiesnow exportsOpenOpportunitiesandLaterProposals.Cross-version refusal. The converter has no older equivalent for either task. The dispatcher now answers a task the caller's release does not define with
UNSUPPORTED_FEATUREanddetails: {task, adcp_version}, where it used to answerVERSION_UNSUPPORTED. The spec requires this forlist_collections. The client already refused such a call before transport. Tests cover the server, the client (MCP and A2A, no dispatch) and the converter. A 3.2get_adcp_capabilitiescaller loseslist_proposalsfromlifecycle_toolsand losesopen_opportunities, and each drop is recorded as a loss.Response envelope.
_response_envelope.pytreats both tasks likelist_products. In the 3.3 prereleases before beta.3, their roots are closed and have nostatus, and beta.3 composes the protocol envelope. The bundled beta.1 / beta.2list_collectionsexamples now pass the SDK's own validation.proposal.created.WebhookSender.prepare_proposal_created/send_proposal_createdbuild a schema-validated payload, andnotification_iddefaults to and must equalproposal_id. Agent-level notification configs now treatproposal.created,proposal.offered,collection_card.*,collection_catalog.bulk_changeandcreative.staged_update_changedas account-anchored. A drift-guard test checks the classification against the enum.MCP tool stubs carry the 3.3 request fields and the correct capability names. The media-buy default trust scope covers both reads. Docs updated: inventory, migration guide,
proposal-surfaces.md,cross-version-conversion.md,AGENTS.md.Deferred
list_proposalsfromProposalStore. The store keeps the legacyget_productsproposal payloads that recipes hydrate from. It does not keep canonical snapshots withdisposition/origin, and it cannot list by account. Documented inproposal-surfaces.md.proposal.offeredandcollection_card.*. Not added.Writes outside the stated scope
src/adcp/_notification_envelope.pyandsrc/adcp/webhook_sender.pyhave small additive changes forproposal.created.src/adcp/types/capabilities.pygains two re-exports. Black reformatted one unrelated expression inserver/principal.py.Test plan
tests/test_list_proposals_collections.py(new)test_notification_preparation.py,test_cross_version_conversion.py,test_decisioning_handler_shims.pymake lint,make typecheck-all-n 3: all pass excepttest_notification_outbox_artifacts.py::test_installed_public_import_schema_and_typing, which errors identically on pristinenextin this sandbox because it builds a wheelBREAKING CHANGE: a server asked for a task its caller's release does not define now fails with
UNSUPPORTED_FEATUREinstead ofVERSION_UNSUPPORTED.validate_platformfails when a platform declareslist_proposalsormedia_buy.collection_catalogwithout the method. Agent-level notification registrations ofproposal.created,proposal.offered,collection_card.*,collection_catalog.bulk_changeorcreative.staged_update_changedrequireall_authorized_accounts: true.Closes #1645
🤖 Generated with Claude Code